package cn.benma666.sjsj.job;

import cn.benma666.dict.Yxzt;
import cn.benma666.domain.SysLogSjlzrz;
import cn.benma666.domain.SysSjglHtrw;
import cn.benma666.domain.XxlJobInfo;
import cn.benma666.exception.MyException;
import cn.benma666.iframe.BasicObject;
import cn.benma666.iframe.Conf;
import cn.benma666.iframe.InterfaceLog;
import cn.benma666.myutils.DateUtil;
import cn.benma666.myutils.StringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.xxl.job.core.context.XxlJobContext;
import com.xxl.job.core.context.XxlJobHelper;
import org.beetl.sql.core.query.LambdaQuery;

import java.math.BigDecimal;
import java.util.List;


/**
 * 抽象JOB父类-基于xxl
 */
public abstract class BasicJob extends BasicObject implements InterfaceLog {
    /**
     * 当参数不能被解析为JSON对象时，可以通过getVal(PARAM)获取原始参数值
     */
    public static final String PARAM = "param";
    /**
     * 按线程缓存参数对象
     */
    protected InheritableThreadLocal<JSONObject> confHolder = new InheritableThreadLocal();
    /**
     * 按线程缓存后台任务
     */
    protected InheritableThreadLocal<SysSjglHtrw> htrwHolder = new InheritableThreadLocal();
    /**
     * 按线程缓存流转日志
     */
    protected InheritableThreadLocal<SysLogSjlzrz> lzrzHolder = new InheritableThreadLocal();
    /**
     * 按线程缓存作业信息
     */
    protected InheritableThreadLocal<XxlJobInfo> jiHolder = new InheritableThreadLocal();
    /**
     * 获取JSON对象的参数
     */
    public JSONObject getConfig(){
        return confHolder.get();
    }

    /**
     * @return 后台任务信息
     */
    public SysSjglHtrw getHtrw(){
        return htrwHolder.get();
    }

    /**
     * @return xxl作业信息
     */
    public XxlJobInfo getJobInfo(){
        return jiHolder.get();
    }

    /**
     * @return 增量时间戳
     */
    public String getZlsjc(){
        return getHtrw().getZlsjc();
    }

    /**
     * 设置增量时间戳，没有增量数据或执行失败时不要更新该信息
     */
    public void setZlsjc(String zlsjc){
        String yzlsjc = getHtrw().getZlsjc();
        if(yzlsjc!=null&&yzlsjc.compareTo(zlsjc)>0){
            throw new MyException("增量时间戳的设置只能比之前的值大，原值："+yzlsjc+"，新值："+zlsjc);
        }
        info("设置增量时间戳：{}",zlsjc);
        getHtrw().setZlsjc(zlsjc);
    }

    /**
     * @return 主键集合
     */
    public String getIds(){
        return getHtrw().getIds();
    }

    /**
     * 设置主键集合，没有增量数据或执行失败时不要更新该信息
     */
    public void setIds(List<?> ids){
        String idsStr = JSON.toJSONString(ids);
        if(isBlank(ids)){
            throw new MyException("主键集合不能设置为空："+idsStr);
        }
        getHtrw().setIds(idsStr);
    }

    /**
     * 设置结果
     */
    public void setJg(int jg){
        getHtrw().setZxzt(jg);
        if(Yxzt.FAILED.getCode()==jg){
            XxlJobHelper.handleFail(lzrzHolder.get().getBz());
        }
    }
    /**
     * 设置读取量
     */
    public void setDql(int dql){
        info("读取数据量：{}",dql);
        lzrzHolder.get().setDql(BigDecimal.valueOf(dql));
    }
    /**
     * 设置处理备注
     */
    public void setBz(String bz){
        info("处理备注：{}",bz);
        lzrzHolder.get().setBz(bz);
    }

    /**
     * 获取参数
     * @param key 支持jsonpath
     * @return 值
     */
    public String getVal(String key){
        return getConfig().getString(key);
    }

    /**
     * 每次运行的初始化方法
     */
    public void runStart(){
        //初始化配置信息
        JSONObject conf = null;
        try {
            conf = JSON.parseObject(XxlJobHelper.getJobParam(), Feature.OrderedField);
        }catch (Exception e){
            debug("参数非json格式");
        }
        if(conf==null){
            conf = new JSONObject();
            conf.put(PARAM,XxlJobHelper.getJobParam());
        }
        confHolder.set(conf);
        //后台任务信息
        LambdaQuery<SysSjglHtrw> query = sqlManager().lambdaQuery(SysSjglHtrw.class);
        SysSjglHtrw htrw = query.andEq(SysSjglHtrw::getYkzj, XxlJobHelper.getJobId())
                .andEq(SysSjglHtrw::getRwlb, Conf.getVal("xxljob.htrwlb")).singleSimple();
        htrwHolder.set(htrw);
        //设置为执行中
        htrw.setZxzt(Yxzt.UNKNOW.getCode());
        //更新后台任务表
        updateHtrw();

        SysLogSjlzrz lzrz = new SysLogSjlzrz();
        lzrzHolder.set(lzrz);
        lzrz.setZymc(htrw.getRwmc());
        lzrz.setKssj(DateUtil.getGabDate());
        lzrz.setZy(XxlJobHelper.getJobId()+"");
    }

    /**
     * 设置流转日志
     * @param xzl 新增量
     * @param cfl 重复量
     * @param wxl 无效量
     */
    public void putLzrz(long xzl, long cfl, long wxl){
        SysLogSjlzrz lzrz = lzrzHolder.get();
        lzrz.setXzl(BigDecimal.valueOf(xzl));
        lzrz.setCfl(BigDecimal.valueOf(cfl));
        lzrz.setWxl(BigDecimal.valueOf(wxl));
        info("新增{}，重复{}，无效{}",xzl,cfl,wxl);
    }

    /**
     * 每次运行结束的方法
     * @param e 当运行失败时传入异常信息
     */
    public void runEnd(Throwable e){
        SysSjglHtrw htrw = htrwHolder.get();
        SysLogSjlzrz lzrz = lzrzHolder.get();
        XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
        if(e!=null||xxlJobContext.getHandleCode()!=XxlJobContext.HANDLE_CODE_SUCCESS){
            //执行失败
            htrw.setZxzt(Yxzt.FAILED.getCode());
        }else if(Yxzt.UNKNOW.getCode() == lzrz.getJg()){
            htrw.setZxzt(Yxzt.SUCCESS.getCode());
        }

        if(Yxzt.SUCCESS.getCode()!=htrw.getZxzt()&&!isBlank(htrw.getZlsjc())){
            debug("非成功状态不能设置增量时间戳：{}",htrw.getZlsjc());
            htrw.setZlsjc(null);
            htrw.setIds(null);
        }
        //更新后台任务表
        updateHtrw();
        if(lzrz.getDql().intValue()>0&&lzrz.getDql().compareTo(lzrz.getCfl())>0){
            //读取量大于0且不是全部重复才记录流转日志
            lzrz.setZlsjc(htrw.getZlsjc());
            lzrz.setJg(htrw.getZxzt());
            lzrz.setJssj(DateUtil.getGabDate());
            sqlManager().insertTemplate(lzrz);
        }
    }

    /**
     * 更新后台任务
     */
    protected void updateHtrw(){
        SysSjglHtrw htrw = htrwHolder.get();
        htrw.setGxsj(DateUtil.getGabDate());
        htrw.setZhgxsj(DateUtil.getGabDate());
        sqlManager().updateTemplateById(htrw);
    }

    /**
     * 线程初始化方法
     */
    public void init(){
        //加载作业信息
        LambdaQuery<XxlJobInfo> jiQuery = sqlManager(Conf.getVal("xxljob.sjzt","xxl_job")).lambdaQuery(XxlJobInfo.class);
        XxlJobInfo ji = jiQuery.andEq(XxlJobInfo::getId, XxlJobHelper.getJobId()).singleSimple();
        if(ji==null){
            throw new MyException("在任务库中没找到该任务，请确认数据载体中的xxl_job载体与调度系统的数据库一致");
        }
        jiHolder.set(ji);
        //后台任务信息
        LambdaQuery<SysSjglHtrw> query = sqlManager().lambdaQuery(SysSjglHtrw.class);
        SysSjglHtrw htrw = query.andEq(SysSjglHtrw::getYkzj, XxlJobHelper.getJobId())
                .andEq(SysSjglHtrw::getRwlb, Conf.getVal("xxljob.htrwlb")).singleSimple();
        if(htrw==null){
            htrw = new SysSjglHtrw();
            htrw.setYkzj(XxlJobHelper.getJobId()+"");
            htrw.setRwlb(Conf.getVal("xxljob.htrwlb"));
            //设置主键
            htrw.setId(StringUtil.getUUIDUpperStr());
            //第一次执行，先插入数据
            sqlManager().insertTemplate(htrw);
        }
        htrw.setRwmc(ji.getJobDesc());
        //设置定时信息，便于后续设置监控参数
        htrw.setDs(ji.getScheduleType()+"/"+ji.getScheduleConf());
        htrwHolder.set(htrw);
        this.updateHtrw();
    }
    private XxlJobHelper xjh;
    public XxlJobHelper getXJjh(){
        if(XxlJobContext.getXxlJobContext()!=null){
            xjh = XxlJobHelper.getCurrXJH();
        }
        return xjh;
    }
    //日志封装
    public void debug(String msg, Object... appendLogArguments){
        if(getXJjh().nlog("DEBUG:"+msg,appendLogArguments)){
            if(appendLogArguments.length>0&&appendLogArguments[appendLogArguments.length-1]
                    instanceof Throwable){
                getXJjh().nlog((Throwable) appendLogArguments[appendLogArguments.length-1]);
            }
        }
        log.debug(msg,appendLogArguments);
    }
    public void info(String msg, Object... appendLogArguments){
        if(getXJjh().nlog("INFO:"+msg,appendLogArguments)){
            if(appendLogArguments.length>0&&appendLogArguments[appendLogArguments.length-1]
                    instanceof Throwable){
                getXJjh().nlog((Throwable) appendLogArguments[appendLogArguments.length-1]);
            }
        }
        log.info(msg,appendLogArguments);
    }
    public void error(String msg, Object... appendLogArguments){
        if(getXJjh().nlog("ERROR:"+msg,appendLogArguments)){
            if(appendLogArguments.length>0&&appendLogArguments[appendLogArguments.length-1]
                    instanceof Throwable){
                getXJjh().nlog((Throwable) appendLogArguments[appendLogArguments.length-1]);
            }
        }
        log.error(msg,appendLogArguments);
    }

    public void debug(String msg,Throwable t) {
        if(getXJjh().nlog("DEBUG:"+msg,t)){
            getXJjh().nlog(t);
        }
        log.debug(msg,t);
    }
    public void info(String msg,Throwable t){
        getXJjh().nlog("INFO:"+msg,t);
        log.info(msg,t);
    }
    public void error(String msg,Throwable t){
        if(getXJjh().nlog("ERROR:"+msg,t)){
            getXJjh().nlog(t);
        }
        log.error(msg,t);
    }
    /**
     * 打印日志
     */
    public void log(String msg, Object... appendLogArguments){
        if(getXJjh().nlog("LOG:"+msg,appendLogArguments)){
            if(appendLogArguments.length>0&&appendLogArguments[appendLogArguments.length-1]
                    instanceof Throwable){
                getXJjh().nlog((Throwable) appendLogArguments[appendLogArguments.length-1]);
            }
        }
        log.info(msg,appendLogArguments);
    }
    /**
     * 打印日志异常
     */
    public void log(String msg,Throwable t){
        if(getXJjh().nlog("LOG:"+msg,t)){
            getXJjh().nlog(t);
        }
        log.error(msg,t);
    }
}
